﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DAWSharp.FileFormats.WavFile;
using DAWSharp.Common.Helpers;

namespace DAWSharp.UI.WPFControls
{
    /// <summary>
    /// Interaction logic for MonoWaveDisplay.xaml
    /// </summary>
    public partial class MonoWaveDisplay : UserControl
    {
        public enum Channel { Left, Right, Mono }

        private WavFile _waveFile;
        private Channel _channel;
        public float zoom { get; set; }
        private float _zoom;
        private int _drawnSampleInterval;
        private int _samplesSinceLastInterval = 0;
        private int _xAxisPosition = 0;
        private float _currentValue = 0.0f;
        private float _peakValue = 0.0f;
        private bool _RMS;
        private int _displayWidth;

        public MonoWaveDisplay(WavFile waveFile, Channel channel, bool RMS, int height, int width)
        {
            InitializeComponent();

            _waveFile = waveFile;
            _channel = channel;
            _RMS = RMS;
            _displayWidth = width;
            zoom = 1.0f;
            _zoom = zoom / 100.0f;
            this.Height = height;
            this.Width = (Int32)(_waveFile.numberOfSamples * _zoom);

            _samplesSinceLastInterval = 0;
            _xAxisPosition = 0;
            _currentValue = 0.0f;
            _peakValue = 0.0f;

            Paint();
        }

        private void Paint()
        {
            _zoom = zoom / 100.0f;
            this.Width = (Int32)(_waveFile.numberOfSamples * _zoom);

            if (_channel == Channel.Mono)
            {
                _drawnSampleInterval = (int)((_waveFile.numberOfSamples) / this.Width);

                if (!_RMS)
                    DrawMono();
                else
                    DrawMonoRMS();
            }
            else
            {
                _drawnSampleInterval = (int)((_waveFile.numberOfSamples / 2) / this.Width);

                if (!_RMS)
                    DrawStereo();
                else
                    DrawStereoRMS();
            }

            Line line = new Line()
            {
                X1 = 0,
                Y1 = this.Height / 2,
                X2 = this.Width,
                Y2 = this.Height / 2,
                StrokeThickness = 1,
                Stroke = System.Windows.Media.Brushes.Black,
                SnapsToDevicePixels = true
            };
            line.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
            thisGrid.Children.Add(line);

            _samplesSinceLastInterval = 0;
            _xAxisPosition = 0;
            _currentValue = 0.0f;
            _peakValue = 0.0f;
        }

        private void DrawMono()
        {
            for (int i = 0; i < _waveFile.numberOfSamples; i++)
            {
                _currentValue = _waveFile.GetSample(i);
                if (Math.Abs(_currentValue) > Math.Abs(_peakValue))
                {
                    _peakValue = _currentValue;
                }
                _samplesSinceLastInterval++;

                if (_samplesSinceLastInterval == _drawnSampleInterval)
                {
                    DrawSample(_peakValue);

                    _xAxisPosition++;
                    _samplesSinceLastInterval = 0;
                    _peakValue = 0.0f;
                }
            }
        }

        private void DrawStereo()
        {
            int offset;
            if (_channel == Channel.Right)
                offset = 1;
            else
                offset = 0;

            for (int i = offset; i < _waveFile.numberOfSamples; i = i + 2)
            {
                _currentValue = _waveFile.GetSample(i);
                if (Math.Abs(_currentValue) > Math.Abs(_peakValue))
                {
                    _peakValue = _currentValue;
                }
                _samplesSinceLastInterval++;

                if (_samplesSinceLastInterval == _drawnSampleInterval)
                {
                    DrawSample(_peakValue);

                    _xAxisPosition++;
                    _samplesSinceLastInterval = 0;
                    _peakValue = 0.0f;
                }
            }
        }

        private void DrawMonoRMS()
        {
            List<float> samples = new List<float>();

            for (int i = 0; i < _waveFile.numberOfSamples; i++)
            {
                samples.Add(_waveFile.GetSample(i));
                _samplesSinceLastInterval++;

                if (_samplesSinceLastInterval == _drawnSampleInterval)
                {
                    DrawSample(ConversionHelper.CalulateRMS(samples));
                    samples.Clear();

                    _xAxisPosition++;
                    _samplesSinceLastInterval = 0;
                }
            }
        }

        private void DrawStereoRMS()
        {
            int offset;
            if (_channel == Channel.Right)
                offset = 1;
            else
                offset = 0;

            List<float> samples = new List<float>();

            for (int i = offset; i < _waveFile.numberOfSamples; i = i + 2)
            {
                samples.Add(_waveFile.GetSample(i));
                _samplesSinceLastInterval++;

                if (_samplesSinceLastInterval == _drawnSampleInterval)
                {
                    DrawSample(ConversionHelper.CalulateRMS(samples));
                    samples.Clear();

                    _xAxisPosition++;
                    _samplesSinceLastInterval = 0;
                }
            }
        }

        private void DrawSample(float value)
        {
            int lineHeight = (int)(value * (this.Height / 2));
            Line line = new Line()
            {
                X1 = _xAxisPosition,
                Y1 = (this.Height / 2) - lineHeight,
                X2 = _xAxisPosition,
                Y2 = (this.Height / 2) + lineHeight,
                StrokeThickness = 1,
                Stroke = System.Windows.Media.Brushes.ForestGreen,
                SnapsToDevicePixels = true
            };
            line.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
            thisGrid.Children.Add(line);
        }
    }
}
